home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / share / gettext / intl / vasnprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  2007-03-05  |  21.9 KB  |  891 lines

  1. /* vsprintf with automatic memory allocation.
  2.    Copyright (C) 1999, 2002-2006 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify it
  5.    under the terms of the GNU Library General Public License as published
  6.    by the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.    Library General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU Library General Public
  15.    License along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  17.    USA.  */
  18.  
  19. /* Tell glibc's <stdio.h> to provide a prototype for snprintf().
  20.    This must come before <config.h> because <config.h> may include
  21.    <features.h>, and once <features.h> has been included, it's too late.  */
  22. #ifndef _GNU_SOURCE
  23. # define _GNU_SOURCE    1
  24. #endif
  25.  
  26. #include <config.h>
  27. #ifndef IN_LIBINTL
  28. # include <alloca.h>
  29. #endif
  30.  
  31. /* Specification.  */
  32. #if WIDE_CHAR_VERSION
  33. # include "vasnwprintf.h"
  34. #else
  35. # include "vasnprintf.h"
  36. #endif
  37.  
  38. #include <stdio.h>    /* snprintf(), sprintf() */
  39. #include <stdlib.h>    /* abort(), malloc(), realloc(), free() */
  40. #include <string.h>    /* memcpy(), strlen() */
  41. #include <errno.h>    /* errno */
  42. #include <limits.h>    /* CHAR_BIT */
  43. #include <float.h>    /* DBL_MAX_EXP, LDBL_MAX_EXP */
  44. #if WIDE_CHAR_VERSION
  45. # include "wprintf-parse.h"
  46. #else
  47. # include "printf-parse.h"
  48. #endif
  49.  
  50. /* Checked size_t computations.  */
  51. #include "xsize.h"
  52.  
  53. #ifdef HAVE_WCHAR_T
  54. # ifdef HAVE_WCSLEN
  55. #  define local_wcslen wcslen
  56. # else
  57.    /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
  58.       a dependency towards this library, here is a local substitute.
  59.       Define this substitute only once, even if this file is included
  60.       twice in the same compilation unit.  */
  61. #  ifndef local_wcslen_defined
  62. #   define local_wcslen_defined 1
  63. static size_t
  64. local_wcslen (const wchar_t *s)
  65. {
  66.   const wchar_t *ptr;
  67.  
  68.   for (ptr = s; *ptr != (wchar_t) 0; ptr++)
  69.     ;
  70.   return ptr - s;
  71. }
  72. #  endif
  73. # endif
  74. #endif
  75.  
  76. #if WIDE_CHAR_VERSION
  77. # define VASNPRINTF vasnwprintf
  78. # define CHAR_T wchar_t
  79. # define DIRECTIVE wchar_t_directive
  80. # define DIRECTIVES wchar_t_directives
  81. # define PRINTF_PARSE wprintf_parse
  82. # define USE_SNPRINTF 1
  83. # if HAVE_DECL__SNWPRINTF
  84.    /* On Windows, the function swprintf() has a different signature than
  85.       on Unix; we use the _snwprintf() function instead.  */
  86. #  define SNPRINTF _snwprintf
  87. # else
  88.    /* Unix.  */
  89. #  define SNPRINTF swprintf
  90. # endif
  91. #else
  92. # define VASNPRINTF vasnprintf
  93. # define CHAR_T char
  94. # define DIRECTIVE char_directive
  95. # define DIRECTIVES char_directives
  96. # define PRINTF_PARSE printf_parse
  97. # define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
  98. # if HAVE_DECL__SNPRINTF
  99.    /* Windows.  */
  100. #  define SNPRINTF _snprintf
  101. # else
  102.    /* Unix.  */
  103. #  define SNPRINTF snprintf
  104. # endif
  105. #endif
  106.  
  107. CHAR_T *
  108. VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
  109. {
  110.   DIRECTIVES d;
  111.   arguments a;
  112.  
  113.   if (PRINTF_PARSE (format, &d, &a) < 0)
  114.     {
  115.       errno = EINVAL;
  116.       return NULL;
  117.     }
  118.  
  119. #define CLEANUP() \
  120.   free (d.dir);                                \
  121.   if (a.arg)                                \
  122.     free (a.arg);
  123.  
  124.   if (printf_fetchargs (args, &a) < 0)
  125.     {
  126.       CLEANUP ();
  127.       errno = EINVAL;
  128.       return NULL;
  129.     }
  130.  
  131.   {
  132.     size_t buf_neededlength;
  133.     CHAR_T *buf;
  134.     CHAR_T *buf_malloced;
  135.     const CHAR_T *cp;
  136.     size_t i;
  137.     DIRECTIVE *dp;
  138.     /* Output string accumulator.  */
  139.     CHAR_T *result;
  140.     size_t allocated;
  141.     size_t length;
  142.  
  143.     /* Allocate a small buffer that will hold a directive passed to
  144.        sprintf or snprintf.  */
  145.     buf_neededlength =
  146.       xsum4 (7, d.max_width_length, d.max_precision_length, 6);
  147. #if HAVE_ALLOCA
  148.     if (buf_neededlength < 4000 / sizeof (CHAR_T))
  149.       {
  150.     buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
  151.     buf_malloced = NULL;
  152.       }
  153.     else
  154. #endif
  155.       {
  156.     size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
  157.     if (size_overflow_p (buf_memsize))
  158.       goto out_of_memory_1;
  159.     buf = (CHAR_T *) malloc (buf_memsize);
  160.     if (buf == NULL)
  161.       goto out_of_memory_1;
  162.     buf_malloced = buf;
  163.       }
  164.  
  165.     if (resultbuf != NULL)
  166.       {
  167.     result = resultbuf;
  168.     allocated = *lengthp;
  169.       }
  170.     else
  171.       {
  172.     result = NULL;
  173.     allocated = 0;
  174.       }
  175.     length = 0;
  176.     /* Invariants:
  177.        result is either == resultbuf or == NULL or malloc-allocated.
  178.        If length > 0, then result != NULL.  */
  179.  
  180.     /* Ensures that allocated >= needed.  Aborts through a jump to
  181.        out_of_memory if needed is SIZE_MAX or otherwise too big.  */
  182. #define ENSURE_ALLOCATION(needed) \
  183.     if ((needed) > allocated)                             \
  184.       {                                         \
  185.     size_t memory_size;                             \
  186.     CHAR_T *memory;                                 \
  187.                                          \
  188.     allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);         \
  189.     if ((needed) > allocated)                         \
  190.       allocated = (needed);                             \
  191.     memory_size = xtimes (allocated, sizeof (CHAR_T));             \
  192.     if (size_overflow_p (memory_size))                     \
  193.       goto out_of_memory;                             \
  194.     if (result == resultbuf || result == NULL)                 \
  195.       memory = (CHAR_T *) malloc (memory_size);                 \
  196.     else                                     \
  197.       memory = (CHAR_T *) realloc (result, memory_size);             \
  198.     if (memory == NULL)                             \
  199.       goto out_of_memory;                             \
  200.     if (result == resultbuf && length > 0)                     \
  201.       memcpy (memory, result, length * sizeof (CHAR_T));             \
  202.     result = memory;                             \
  203.       }
  204.  
  205.     for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
  206.       {
  207.     if (cp != dp->dir_start)
  208.       {
  209.         size_t n = dp->dir_start - cp;
  210.         size_t augmented_length = xsum (length, n);
  211.  
  212.         ENSURE_ALLOCATION (augmented_length);
  213.         memcpy (result + length, cp, n * sizeof (CHAR_T));
  214.         length = augmented_length;
  215.       }
  216.     if (i == d.count)
  217.       break;
  218.  
  219.     /* Execute a single directive.  */
  220.     if (dp->conversion == '%')
  221.       {
  222.         size_t augmented_length;
  223.  
  224.         if (!(dp->arg_index == ARG_NONE))
  225.           abort ();
  226.         augmented_length = xsum (length, 1);
  227.         ENSURE_ALLOCATION (augmented_length);
  228.         result[length] = '%';
  229.         length = augmented_length;
  230.       }
  231.     else
  232.       {
  233.         if (!(dp->arg_index != ARG_NONE))
  234.           abort ();
  235.  
  236.         if (dp->conversion == 'n')
  237.           {
  238.         switch (a.arg[dp->arg_index].type)
  239.           {
  240.           case TYPE_COUNT_SCHAR_POINTER:
  241.             *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
  242.             break;
  243.           case TYPE_COUNT_SHORT_POINTER:
  244.             *a.arg[dp->arg_index].a.a_count_short_pointer = length;
  245.             break;
  246.           case TYPE_COUNT_INT_POINTER:
  247.             *a.arg[dp->arg_index].a.a_count_int_pointer = length;
  248.             break;
  249.           case TYPE_COUNT_LONGINT_POINTER:
  250.             *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
  251.             break;
  252. #ifdef HAVE_LONG_LONG_INT
  253.           case TYPE_COUNT_LONGLONGINT_POINTER:
  254.             *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
  255.             break;
  256. #endif
  257.           default:
  258.             abort ();
  259.           }
  260.           }
  261.         else
  262.           {
  263.         arg_type type = a.arg[dp->arg_index].type;
  264.         CHAR_T *p;
  265.         unsigned int prefix_count;
  266.         int prefixes[2];
  267. #if !USE_SNPRINTF
  268.         size_t tmp_length;
  269.         CHAR_T tmpbuf[700];
  270.         CHAR_T *tmp;
  271.  
  272.         /* Allocate a temporary buffer of sufficient size for calling
  273.            sprintf.  */
  274.         {
  275.           size_t width;
  276.           size_t precision;
  277.  
  278.           width = 0;
  279.           if (dp->width_start != dp->width_end)
  280.             {
  281.               if (dp->width_arg_index != ARG_NONE)
  282.             {
  283.               int arg;
  284.  
  285.               if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
  286.                 abort ();
  287.               arg = a.arg[dp->width_arg_index].a.a_int;
  288.               width = (arg < 0 ? (unsigned int) (-arg) : arg);
  289.             }
  290.               else
  291.             {
  292.               const CHAR_T *digitp = dp->width_start;
  293.  
  294.               do
  295.                 width = xsum (xtimes (width, 10), *digitp++ - '0');
  296.               while (digitp != dp->width_end);
  297.             }
  298.             }
  299.  
  300.           precision = 6;
  301.           if (dp->precision_start != dp->precision_end)
  302.             {
  303.               if (dp->precision_arg_index != ARG_NONE)
  304.             {
  305.               int arg;
  306.  
  307.               if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
  308.                 abort ();
  309.               arg = a.arg[dp->precision_arg_index].a.a_int;
  310.               precision = (arg < 0 ? 0 : arg);
  311.             }
  312.               else
  313.             {
  314.               const CHAR_T *digitp = dp->precision_start + 1;
  315.  
  316.               precision = 0;
  317.               while (digitp != dp->precision_end)
  318.                 precision = xsum (xtimes (precision, 10), *digitp++ - '0');
  319.             }
  320.             }
  321.  
  322.           switch (dp->conversion)
  323.             {
  324.  
  325.             case 'd': case 'i': case 'u':
  326. # ifdef HAVE_LONG_LONG_INT
  327.               if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
  328.             tmp_length =
  329.               (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
  330.                       * 0.30103 /* binary -> decimal */
  331.                      )
  332.               + 1; /* turn floor into ceil */
  333.               else
  334. # endif
  335.               if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
  336.             tmp_length =
  337.               (unsigned int) (sizeof (unsigned long) * CHAR_BIT
  338.                       * 0.30103 /* binary -> decimal */
  339.                      )
  340.               + 1; /* turn floor into ceil */
  341.               else
  342.             tmp_length =
  343.               (unsigned int) (sizeof (unsigned int) * CHAR_BIT
  344.                       * 0.30103 /* binary -> decimal */
  345.                      )
  346.               + 1; /* turn floor into ceil */
  347.               if (tmp_length < precision)
  348.             tmp_length = precision;
  349.               /* Multiply by 2, as an estimate for FLAG_GROUP.  */
  350.               tmp_length = xsum (tmp_length, tmp_length);
  351.               /* Add 1, to account for a leading sign.  */
  352.               tmp_length = xsum (tmp_length, 1);
  353.               break;
  354.  
  355.             case 'o':
  356. # ifdef HAVE_LONG_LONG_INT
  357.               if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
  358.             tmp_length =
  359.               (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
  360.                       * 0.333334 /* binary -> octal */
  361.                      )
  362.               + 1; /* turn floor into ceil */
  363.               else
  364. # endif
  365.               if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
  366.             tmp_length =
  367.               (unsigned int) (sizeof (unsigned long) * CHAR_BIT
  368.                       * 0.333334 /* binary -> octal */
  369.                      )
  370.               + 1; /* turn floor into ceil */
  371.               else
  372.             tmp_length =
  373.               (unsigned int) (sizeof (unsigned int) * CHAR_BIT
  374.                       * 0.333334 /* binary -> octal */
  375.                      )
  376.               + 1; /* turn floor into ceil */
  377.               if (tmp_length < precision)
  378.             tmp_length = precision;
  379.               /* Add 1, to account for a leading sign.  */
  380.               tmp_length = xsum (tmp_length, 1);
  381.               break;
  382.  
  383.             case 'x': case 'X':
  384. # ifdef HAVE_LONG_LONG_INT
  385.               if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
  386.             tmp_length =
  387.               (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
  388.                       * 0.25 /* binary -> hexadecimal */
  389.                      )
  390.               + 1; /* turn floor into ceil */
  391.               else
  392. # endif
  393.               if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
  394.             tmp_length =
  395.               (unsigned int) (sizeof (unsigned long) * CHAR_BIT
  396.                       * 0.25 /* binary -> hexadecimal */
  397.                      )
  398.               + 1; /* turn floor into ceil */
  399.               else
  400.             tmp_length =
  401.               (unsigned int) (sizeof (unsigned int) * CHAR_BIT
  402.                       * 0.25 /* binary -> hexadecimal */
  403.                      )
  404.               + 1; /* turn floor into ceil */
  405.               if (tmp_length < precision)
  406.             tmp_length = precision;
  407.               /* Add 2, to account for a leading sign or alternate form.  */
  408.               tmp_length = xsum (tmp_length, 2);
  409.               break;
  410.  
  411.             case 'f': case 'F':
  412. # ifdef HAVE_LONG_DOUBLE
  413.               if (type == TYPE_LONGDOUBLE)
  414.             tmp_length =
  415.               (unsigned int) (LDBL_MAX_EXP
  416.                       * 0.30103 /* binary -> decimal */
  417.                       * 2 /* estimate for FLAG_GROUP */
  418.                      )
  419.               + 1 /* turn floor into ceil */
  420.               + 10; /* sign, decimal point etc. */
  421.               else
  422. # endif
  423.             tmp_length =
  424.               (unsigned int) (DBL_MAX_EXP
  425.                       * 0.30103 /* binary -> decimal */
  426.                       * 2 /* estimate for FLAG_GROUP */
  427.                      )
  428.               + 1 /* turn floor into ceil */
  429.               + 10; /* sign, decimal point etc. */
  430.               tmp_length = xsum (tmp_length, precision);
  431.               break;
  432.  
  433.             case 'e': case 'E': case 'g': case 'G':
  434.             case 'a': case 'A':
  435.               tmp_length =
  436.             12; /* sign, decimal point, exponent etc. */
  437.               tmp_length = xsum (tmp_length, precision);
  438.               break;
  439.  
  440.             case 'c':
  441. # if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
  442.               if (type == TYPE_WIDE_CHAR)
  443.             tmp_length = MB_CUR_MAX;
  444.               else
  445. # endif
  446.             tmp_length = 1;
  447.               break;
  448.  
  449.             case 's':
  450. # ifdef HAVE_WCHAR_T
  451.               if (type == TYPE_WIDE_STRING)
  452.             {
  453.               tmp_length =
  454.                 local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
  455.  
  456. #  if !WIDE_CHAR_VERSION
  457.               tmp_length = xtimes (tmp_length, MB_CUR_MAX);
  458. #  endif
  459.             }
  460.               else
  461. # endif
  462.             tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
  463.               break;
  464.  
  465.             case 'p':
  466.               tmp_length =
  467.             (unsigned int) (sizeof (void *) * CHAR_BIT
  468.                     * 0.25 /* binary -> hexadecimal */
  469.                        )
  470.               + 1 /* turn floor into ceil */
  471.               + 2; /* account for leading 0x */
  472.               break;
  473.  
  474.             default:
  475.               abort ();
  476.             }
  477.  
  478.           if (tmp_length < width)
  479.             tmp_length = width;
  480.  
  481.           tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
  482.         }
  483.  
  484.         if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
  485.           tmp = tmpbuf;
  486.         else
  487.           {
  488.             size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
  489.  
  490.             if (size_overflow_p (tmp_memsize))
  491.               /* Overflow, would lead to out of memory.  */
  492.               goto out_of_memory;
  493.             tmp = (CHAR_T *) malloc (tmp_memsize);
  494.             if (tmp == NULL)
  495.               /* Out of memory.  */
  496.               goto out_of_memory;
  497.           }
  498. #endif
  499.  
  500.         /* Construct the format string for calling snprintf or
  501.            sprintf.  */
  502.         p = buf;
  503.         *p++ = '%';
  504.         if (dp->flags & FLAG_GROUP)
  505.           *p++ = '\'';
  506.         if (dp->flags & FLAG_LEFT)
  507.           *p++ = '-';
  508.         if (dp->flags & FLAG_SHOWSIGN)
  509.           *p++ = '+';
  510.         if (dp->flags & FLAG_SPACE)
  511.           *p++ = ' ';
  512.         if (dp->flags & FLAG_ALT)
  513.           *p++ = '#';
  514.         if (dp->flags & FLAG_ZERO)
  515.           *p++ = '0';
  516.         if (dp->width_start != dp->width_end)
  517.           {
  518.             size_t n = dp->width_end - dp->width_start;
  519.             memcpy (p, dp->width_start, n * sizeof (CHAR_T));
  520.             p += n;
  521.           }
  522.         if (dp->precision_start != dp->precision_end)
  523.           {
  524.             size_t n = dp->precision_end - dp->precision_start;
  525.             memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
  526.             p += n;
  527.           }
  528.  
  529.         switch (type)
  530.           {
  531. #ifdef HAVE_LONG_LONG_INT
  532.           case TYPE_LONGLONGINT:
  533.           case TYPE_ULONGLONGINT:
  534.             *p++ = 'l';
  535.             /*FALLTHROUGH*/
  536. #endif
  537.           case TYPE_LONGINT:
  538.           case TYPE_ULONGINT:
  539. #ifdef HAVE_WINT_T
  540.           case TYPE_WIDE_CHAR:
  541. #endif
  542. #ifdef HAVE_WCHAR_T
  543.           case TYPE_WIDE_STRING:
  544. #endif
  545.             *p++ = 'l';
  546.             break;
  547. #ifdef HAVE_LONG_DOUBLE
  548.           case TYPE_LONGDOUBLE:
  549.             *p++ = 'L';
  550.             break;
  551. #endif
  552.           default:
  553.             break;
  554.           }
  555.         *p = dp->conversion;
  556. #if USE_SNPRINTF
  557.         p[1] = '%';
  558.         p[2] = 'n';
  559.         p[3] = '\0';
  560. #else
  561.         p[1] = '\0';
  562. #endif
  563.  
  564.         /* Construct the arguments for calling snprintf or sprintf.  */
  565.         prefix_count = 0;
  566.         if (dp->width_arg_index != ARG_NONE)
  567.           {
  568.             if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
  569.               abort ();
  570.             prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
  571.           }
  572.         if (dp->precision_arg_index != ARG_NONE)
  573.           {
  574.             if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
  575.               abort ();
  576.             prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
  577.           }
  578.  
  579. #if USE_SNPRINTF
  580.         /* Prepare checking whether snprintf returns the count
  581.            via %n.  */
  582.         ENSURE_ALLOCATION (xsum (length, 1));
  583.         result[length] = '\0';
  584. #endif
  585.  
  586.         for (;;)
  587.           {
  588.             size_t maxlen;
  589.             int count;
  590.             int retcount;
  591.  
  592.             maxlen = allocated - length;
  593.             count = -1;
  594.             retcount = 0;
  595.  
  596. #if USE_SNPRINTF
  597. # define SNPRINTF_BUF(arg) \
  598.             switch (prefix_count)                    \
  599.               {                                \
  600.               case 0:                            \
  601.             retcount = SNPRINTF (result + length, maxlen, buf,  \
  602.                          arg, &count);            \
  603.             break;                            \
  604.               case 1:                            \
  605.             retcount = SNPRINTF (result + length, maxlen, buf,  \
  606.                          prefixes[0], arg, &count);        \
  607.             break;                            \
  608.               case 2:                            \
  609.             retcount = SNPRINTF (result + length, maxlen, buf,  \
  610.                          prefixes[0], prefixes[1], arg, \
  611.                          &count);                \
  612.             break;                            \
  613.               default:                            \
  614.             abort ();                        \
  615.               }
  616. #else
  617. # define SNPRINTF_BUF(arg) \
  618.             switch (prefix_count)                    \
  619.               {                                \
  620.               case 0:                            \
  621.             count = sprintf (tmp, buf, arg);            \
  622.             break;                            \
  623.               case 1:                            \
  624.             count = sprintf (tmp, buf, prefixes[0], arg);        \
  625.             break;                            \
  626.               case 2:                            \
  627.             count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
  628.                      arg);                    \
  629.             break;                            \
  630.               default:                            \
  631.             abort ();                        \
  632.               }
  633. #endif
  634.  
  635.             switch (type)
  636.               {
  637.               case TYPE_SCHAR:
  638.             {
  639.               int arg = a.arg[dp->arg_index].a.a_schar;
  640.               SNPRINTF_BUF (arg);
  641.             }
  642.             break;
  643.               case TYPE_UCHAR:
  644.             {
  645.               unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
  646.               SNPRINTF_BUF (arg);
  647.             }
  648.             break;
  649.               case TYPE_SHORT:
  650.             {
  651.               int arg = a.arg[dp->arg_index].a.a_short;
  652.               SNPRINTF_BUF (arg);
  653.             }
  654.             break;
  655.               case TYPE_USHORT:
  656.             {
  657.               unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
  658.               SNPRINTF_BUF (arg);
  659.             }
  660.             break;
  661.               case TYPE_INT:
  662.             {
  663.               int arg = a.arg[dp->arg_index].a.a_int;
  664.               SNPRINTF_BUF (arg);
  665.             }
  666.             break;
  667.               case TYPE_UINT:
  668.             {
  669.               unsigned int arg = a.arg[dp->arg_index].a.a_uint;
  670.               SNPRINTF_BUF (arg);
  671.             }
  672.             break;
  673.               case TYPE_LONGINT:
  674.             {
  675.               long int arg = a.arg[dp->arg_index].a.a_longint;
  676.               SNPRINTF_BUF (arg);
  677.             }
  678.             break;
  679.               case TYPE_ULONGINT:
  680.             {
  681.               unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
  682.               SNPRINTF_BUF (arg);
  683.             }
  684.             break;
  685. #ifdef HAVE_LONG_LONG_INT
  686.               case TYPE_LONGLONGINT:
  687.             {
  688.               long long int arg = a.arg[dp->arg_index].a.a_longlongint;
  689.               SNPRINTF_BUF (arg);
  690.             }
  691.             break;
  692.               case TYPE_ULONGLONGINT:
  693.             {
  694.               unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
  695.               SNPRINTF_BUF (arg);
  696.             }
  697.             break;
  698. #endif
  699.               case TYPE_DOUBLE:
  700.             {
  701.               double arg = a.arg[dp->arg_index].a.a_double;
  702.               SNPRINTF_BUF (arg);
  703.             }
  704.             break;
  705. #ifdef HAVE_LONG_DOUBLE
  706.               case TYPE_LONGDOUBLE:
  707.             {
  708.               long double arg = a.arg[dp->arg_index].a.a_longdouble;
  709.               SNPRINTF_BUF (arg);
  710.             }
  711.             break;
  712. #endif
  713.               case TYPE_CHAR:
  714.             {
  715.               int arg = a.arg[dp->arg_index].a.a_char;
  716.               SNPRINTF_BUF (arg);
  717.             }
  718.             break;
  719. #ifdef HAVE_WINT_T
  720.               case TYPE_WIDE_CHAR:
  721.             {
  722.               wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
  723.               SNPRINTF_BUF (arg);
  724.             }
  725.             break;
  726. #endif
  727.               case TYPE_STRING:
  728.             {
  729.               const char *arg = a.arg[dp->arg_index].a.a_string;
  730.               SNPRINTF_BUF (arg);
  731.             }
  732.             break;
  733. #ifdef HAVE_WCHAR_T
  734.               case TYPE_WIDE_STRING:
  735.             {
  736.               const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
  737.               SNPRINTF_BUF (arg);
  738.             }
  739.             break;
  740. #endif
  741.               case TYPE_POINTER:
  742.             {
  743.               void *arg = a.arg[dp->arg_index].a.a_pointer;
  744.               SNPRINTF_BUF (arg);
  745.             }
  746.             break;
  747.               default:
  748.             abort ();
  749.               }
  750.  
  751. #if USE_SNPRINTF
  752.             /* Portability: Not all implementations of snprintf()
  753.                are ISO C 99 compliant.  Determine the number of
  754.                bytes that snprintf() has produced or would have
  755.                produced.  */
  756.             if (count >= 0)
  757.               {
  758.             /* Verify that snprintf() has NUL-terminated its
  759.                result.  */
  760.             if (count < maxlen && result[length + count] != '\0')
  761.               abort ();
  762.             /* Portability hack.  */
  763.             if (retcount > count)
  764.               count = retcount;
  765.               }
  766.             else
  767.               {
  768.             /* snprintf() doesn't understand the '%n'
  769.                directive.  */
  770.             if (p[1] != '\0')
  771.               {
  772.                 /* Don't use the '%n' directive; instead, look
  773.                    at the snprintf() return value.  */
  774.                 p[1] = '\0';
  775.                 continue;
  776.               }
  777.             else
  778.               {
  779.                 /* Look at the snprintf() return value.  */
  780.                 if (retcount < 0)
  781.                   {
  782.                 /* HP-UX 10.20 snprintf() is doubly deficient:
  783.                    It doesn't understand the '%n' directive,
  784.                    *and* it returns -1 (rather than the length
  785.                    that would have been required) when the
  786.                    buffer is too small.  */
  787.                 size_t bigger_need =
  788.                   xsum (xtimes (allocated, 2), 12);
  789.                 ENSURE_ALLOCATION (bigger_need);
  790.                 continue;
  791.                   }
  792.                 else
  793.                   count = retcount;
  794.               }
  795.               }
  796. #endif
  797.  
  798.             /* Attempt to handle failure.  */
  799.             if (count < 0)
  800.               {
  801.             if (!(result == resultbuf || result == NULL))
  802.               free (result);
  803.             if (buf_malloced != NULL)
  804.               free (buf_malloced);
  805.             CLEANUP ();
  806.             errno = EINVAL;
  807.             return NULL;
  808.               }
  809.  
  810. #if !USE_SNPRINTF
  811.             if (count >= tmp_length)
  812.               /* tmp_length was incorrectly calculated - fix the
  813.              code above!  */
  814.               abort ();
  815. #endif
  816.  
  817.             /* Make room for the result.  */
  818.             if (count >= maxlen)
  819.               {
  820.             /* Need at least count bytes.  But allocate
  821.                proportionally, to avoid looping eternally if
  822.                snprintf() reports a too small count.  */
  823.             size_t n =
  824.               xmax (xsum (length, count), xtimes (allocated, 2));
  825.  
  826.             ENSURE_ALLOCATION (n);
  827. #if USE_SNPRINTF
  828.             continue;
  829. #endif
  830.               }
  831.  
  832. #if USE_SNPRINTF
  833.             /* The snprintf() result did fit.  */
  834. #else
  835.             /* Append the sprintf() result.  */
  836.             memcpy (result + length, tmp, count * sizeof (CHAR_T));
  837.             if (tmp != tmpbuf)
  838.               free (tmp);
  839. #endif
  840.  
  841.             length += count;
  842.             break;
  843.           }
  844.           }
  845.       }
  846.       }
  847.  
  848.     /* Add the final NUL.  */
  849.     ENSURE_ALLOCATION (xsum (length, 1));
  850.     result[length] = '\0';
  851.  
  852.     if (result != resultbuf && length + 1 < allocated)
  853.       {
  854.     /* Shrink the allocated memory if possible.  */
  855.     CHAR_T *memory;
  856.  
  857.     memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
  858.     if (memory != NULL)
  859.       result = memory;
  860.       }
  861.  
  862.     if (buf_malloced != NULL)
  863.       free (buf_malloced);
  864.     CLEANUP ();
  865.     *lengthp = length;
  866.     /* Note that we can produce a big string of a length > INT_MAX.  POSIX
  867.        says that snprintf() fails with errno = EOVERFLOW in this case, but
  868.        that's only because snprintf() returns an 'int'.  This function does
  869.        not have this limitation.  */
  870.     return result;
  871.  
  872.   out_of_memory:
  873.     if (!(result == resultbuf || result == NULL))
  874.       free (result);
  875.     if (buf_malloced != NULL)
  876.       free (buf_malloced);
  877.   out_of_memory_1:
  878.     CLEANUP ();
  879.     errno = ENOMEM;
  880.     return NULL;
  881.   }
  882. }
  883.  
  884. #undef SNPRINTF
  885. #undef USE_SNPRINTF
  886. #undef PRINTF_PARSE
  887. #undef DIRECTIVES
  888. #undef DIRECTIVE
  889. #undef CHAR_T
  890. #undef VASNPRINTF
  891.